package com.dianwoba.core.interceptor;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.dianwoba.core.cache.Cache;
import com.dianwoba.core.cache.CacheKey;
import com.dianwoba.core.cache.CacheService;
import com.dianwoba.core.datasource.DataSourceHolder;
import com.dianwoba.core.datasource.Slave;

public class BusinessMethodInterceptor implements MethodInterceptor {

	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private CacheService cacheService;
	
	private Boolean needRoutingDatasource;

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Method thisMethod = invocation.getMethod();
		
		/**
		 * 数据源切换
		 */
		routingDatasource(invocation);
		
		/**
		 * 缓存处理
		 */
		if (thisMethod.isAnnotationPresent(Cache.class)) {
			Cache annotation = thisMethod.getAnnotation(Cache.class);
			Class<?> returnType = thisMethod.getReturnType();
			if (returnType != null && !"void".equals(returnType.getName())) {
				Object cache = null;
				try {
					CacheKey key = new CacheKey(thisMethod.getDeclaringClass(), thisMethod, invocation.getArguments());
					if(!annotation.requireNew()){
						cache = cacheService.getCache(key.toString());
//						logger.debug("Cache Annotation process result from Redis, from method {}", thisMethod);
					}
					if (cache == null) {
						cache = invocation.proceed();
						try {
							cacheService.putCache(key.toString(), cache, annotation.expire());
						} catch (Exception e) {
							logger.warn("Cache Annotation process PUT CACHE exception.", e);
						}
//						logger.debug("Cache Annotation process result from Method execute, from method {}", thisMethod);
					}
					return cache;
				} catch (Exception e) {
					logger.warn("Cache Annotation process exception.", e);
				}
			}
		}
		
		return invocation.proceed();
	}
	
	/**
	 * 根据业务自定义使用主库条件，默认false使用从库
	 * @param invocation
	 * @return
	 */
	protected boolean customMasterConditions(MethodInvocation invocation){
		return false;
	}
	
	/**
	 * 切换数据源
	 * <pre>
	 * 1,Cobar注解一定使用Cobar
	 * 2,OtherDs注解一定使用OtherDs，目前主要是turbine中有使用
	 * 2,Master
	 * </pre>
	 * @param invocation
	 */
	private void routingDatasource(MethodInvocation invocation) {
		if (BooleanUtils.isFalse(needRoutingDatasource)) {
			return;
		}
		final Method thisMethod = invocation.getMethod();
		
		if (thisMethod.isAnnotationPresent(Slave.class)) {
			final String lookupKey = thisMethod.getAnnotation(Slave.class).lookupKey();
			DataSourceHolder.setSlave(lookupKey);
			logger.debug(thisMethod.toString() + " execute with datasource is " + lookupKey);
		} else {
			DataSourceHolder.setMaster();
		}
	}

	public void setNeedRoutingDatasource(Boolean needRoutingDatasource) {
		this.needRoutingDatasource = needRoutingDatasource;
	}
	
}
